﻿using System;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using MiscUtil;

namespace Kise.LprCapturer
{
    class ParameterReader
    {

        private ParameterReading Reading = new ParameterReading();

        private const uint GET_VIDEO_SPEED_TOPPOINT = 0xFFFF003E;
        private const uint GET_VIDEO_SPEED_BOTTOMPOINT = 0xFFFF003F;
        private const uint GET_VIDEO_SPEED_WH = 0xFFFF0040;


        private readonly IPEndPoint _endPoint;
        public event EventHandler<MiscUtil.EventArgs<ParameterReading>> ReadingCompleted;

        public void RaiseReadingCompleted(EventArgs<ParameterReading> e)
        {
            EventHandler<EventArgs<ParameterReading>> handler = ReadingCompleted;
            if (handler != null) handler(this, e);
        }


        public ParameterReader(System.Net.IPEndPoint endPoint)
        {
            _endPoint = endPoint;
        }

        public void Start()
        {
            Task.Factory.StartNew(StartCore);
        }

        private void StartCore()
        {
            while (true)
            {
                TcpClient client;
                try
                {
                    client = new TcpClient();
                    client.Connect(_endPoint);
                }
                catch (Exception ex)
                {
                    System.Threading.Thread.Sleep(500);
                    continue;
                }

                var stream = client.GetStream();

                SendRequest(stream, GET_VIDEO_SPEED_BOTTOMPOINT);
                SendRequest(stream, GET_VIDEO_SPEED_TOPPOINT);
                SendRequest(stream, GET_VIDEO_SPEED_WH);

                var topRead = false;
                var bottomRead = false;
                var whRead = false;

                while (true)
                {

                    var buffer = new byte[12];
                    var read = Helper.ReadLength(buffer, 0, buffer.Length, stream);
                    if (read != buffer.Length)
                    {
                        RaiseReadingCompleted(new EventArgs<ParameterReading>(new ParameterReading() { Error = new Exception("connection closed prematurely") }));
                        break;
                    }

                    var type = BitConverter.ToUInt32(buffer, 0);
                    switch (type)
                    {
                        case GET_VIDEO_SPEED_TOPPOINT:
                        case GET_VIDEO_SPEED_BOTTOMPOINT:
                            {
                                uint x2;
                                uint y2;
                                uint y1;
                                uint x1;
                                uint t;
                                GetReading(buffer, out x2, out y2, out y1, out x1);
                                if (type == GET_VIDEO_SPEED_TOPPOINT)
                                {
                                    Reading.LeftTop = new Point((int)x1, (int)y1);
                                    Reading.RightTop = new Point((int)x2, (int)y2);
                                    topRead = true;
                                }
                                else if (type == GET_VIDEO_SPEED_BOTTOMPOINT)
                                {
                                    Reading.LeftBottom = new Point((int)x1, (int)y1);
                                    Reading.RightBottom = new Point((int)x2, (int)y2);
                                    bottomRead = true;
                                }
                                break;
                            }
                        case GET_VIDEO_SPEED_WH:
                            {
                                var w = BitConverter.ToSingle(buffer, 4);
                                var h = BitConverter.ToSingle(buffer, 8);
                                Reading.Width = w;
                                Reading.Height = h;
                                whRead = true;
                                break;
                            }
                    }

                    if (topRead && bottomRead && whRead)
                    {
                        RaiseReadingCompleted(new EventArgs<ParameterReading>(Reading));
                        client.Client.Shutdown(SocketShutdown.Both);
                        return;
                    }

                }

            }
        }

        private static void GetReading(byte[] buffer, out uint x2, out uint y2, out uint y1, out uint x1)
        {
            var p1 = BitConverter.ToUInt32(buffer, 4);
            var p2 = BitConverter.ToUInt32(buffer, 8);
            x1 = p1 >> 16;
            y1 = p1 & 0x0000FFFF;
            x2 = p2 >> 16;
            y2 = p2 & 0x0000FFFF;
        }

        private static void SendRequest(Stream stream, uint type)
        {
            var writer = new MiscUtil.IO.EndianBinaryWriter(MiscUtil.Conversion.EndianBitConverter.Little, stream);
            writer.Write(type);
            writer.Write(0u);
            writer.Write(0u);
            writer.Flush();
        }

    }
}
